/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 */

import path from 'path';

import { cloneDeep } from '@baize/wdk';
import { doCompilePluginTypeCheck, TrackAPI } from '@ohos/hvigor';
import fse from 'fs-extra';

import { getHookFilePath } from '../../../common/build-option-path-info.js';
import { CoreProjectProfile } from '../../../common/global/core-project-profile.js';
import { moduleOptionPathInfo } from '../../../common/module-option-path-info.js';
import { ohosTrace } from '../../../common/trace/ohos-trace.js';
import { CommonConst } from '../../../const/common-const.js';
import { CoreModuleModelImpl } from '../../../model/module/core-module-model-impl.js';
import { ModuleBuildProfile } from '../../../options/build/module-build-profile.js';
import { ProjectBuildProfile } from '../../../options/build/project-build-profile.js';
import { ModuleJson } from '../../../options/configure/module-json-options.js';
import { BuildModeManager } from '../../../project/build-option/build-mode-manager.js';
import { ModuleTaskService } from '../../../tasks/service/module-task-service.js';
import { InjectUtil } from '../../../utils/inject-util.js';
import { harModuleBuildProfileLoader } from '../../../utils/loader/file/har-module-build-profile-loader.js';
import { moduleBuildProfileLoader } from '../../../utils/loader/file/module-build-profile-loader.js';
import { ohPackageLoader } from '../../../utils/loader/file/oh-package-loader.js';
import { resModelLoader } from '../../../utils/loader/file/res-model-loader.js';
import { OhosLogger } from '../../../utils/log/ohos-logger.js';
import { AbstractModulePlugin } from '../../common/abstract-module-plugin.js';
import { OhosModuleContext, OhpmDependencyInfo, Target } from '../plugin-context.js';

/**
 * Module级别的上下文信息
 */
export class OhosModuleContextImpl implements OhosModuleContext {
  private readonly modulePlugin: AbstractModulePlugin;
  private readonly targetArr: Target[];
  private readonly taskService: ModuleTaskService;
  private readonly moduleOhPackagePath: string;
  private logger = OhosLogger.getLogger(OhosModuleContextImpl.name);

  constructor(modulePlugin: AbstractModulePlugin) {
    this.modulePlugin = modulePlugin;
    this.taskService = this.modulePlugin.getTaskService() as ModuleTaskService;
    this.targetArr = this.taskService.getTargets();
    this.moduleOhPackagePath = this.modulePlugin.getModuleModel()?.getOhPackageJson5Path() as string;
  }

  @TrackAPI targets(callback: (target: Target) => void): void {
    this.targetArr.forEach((target: Target) => callback(target));
  }

  @TrackAPI getModuleName(): string {
    return this.modulePlugin.getModuleModel()!.getModule()!.getName();
  }

  @TrackAPI getModulePath(): string {
    return this.modulePlugin.getModuleModel()!.getModule()!.getNodeDir();
  }

  @TrackAPI getModuleType(): string {
    return this.modulePlugin.getModuleModel()!.getModuleType();
  }

  @TrackAPI getBuildProductRootPath(): string {
    return path.resolve(InjectUtil.getModuleBuildRootPath(this.getModulePath()), this.getModulePath());
  }

  @TrackAPI getOhpmDependencyInfo(): Record<string, OhpmDependencyInfo> {
    return this.taskService.getOhpmDependencyInfo();
  }

  @TrackAPI getOhpmRemoteHspDependencyInfo(isSigned = false): Record<string, OhpmDependencyInfo> {
    const projectPath = this.taskService.getProjectModel()!.getProject().getNodeDir();
    const productBuildOpt: ProjectBuildProfile.ProductBuildOpt = CoreProjectProfile.getInstance(projectPath).getCurrentProductOpt();
    return this.taskService.getOhpmRemoteHspDependencies(this.taskService, productBuildOpt.name, isSigned);
  }

  @TrackAPI getBuildProfileOpt(): ModuleBuildProfile.ModuleBuildOpt {
    return cloneDeep(
      this.taskService.getModuleModel().isHarModule()
        ? harModuleBuildProfileLoader.getBuildProfile(this.getModuleName())
        : moduleBuildProfileLoader.getBuildProfile(this.getModuleName()),
    );
  }

  @TrackAPI getModuleJsonOpt(): ModuleJson.ModuleOptObj {
    const moduleJsonPath = path.resolve(this.taskService.getProjectModel().getProjectDir(), this.getModulePath(), `src/main/${CommonConst.MODULE_JSON5}`);
    return cloneDeep(resModelLoader.getModuleJson(moduleJsonPath));
  }

  @TrackAPI setBuildProfileOpt(buildProfileOpt: ModuleBuildProfile.ModuleBuildOpt): void {
    if (this.taskService.isFaMode()) {
      this.logger.printErrorExit('FA_MODE_NOT_SUPPORT_MODIFY_FILE', ['buildProfile']);
    }
    this.taskService.getModuleModel().isHarModule()
      ? harModuleBuildProfileLoader.setBuildProfileJson5Obj(this.getModuleName(), buildProfileOpt)
      : moduleBuildProfileLoader.setBuildProfileJson5Obj(this.getModuleName(), buildProfileOpt);

    // 顺序不能变 设置后需要刷新已经合并的数据项
    this.modulePlugin.getModuleModel()?.refreshData();
    this.modulePlugin.initBuildOptionMap(getHookFilePath());
    this.modulePlugin.refreshTargetServiceList();
  }

  @TrackAPI setModuleJsonOpt(moduleJsonOpt: ModuleJson.ModuleOptObj): void {
    if (this.taskService.isFaMode()) {
      this.logger.printErrorExit('FA_MODE_NOT_SUPPORT_MODIFY_FILE', ['module.json5']);
    }
    const moduleJsonPath = path.resolve(this.taskService.getProjectModel().getProjectDir(), this.getModulePath(), `src/main/${CommonConst.MODULE_JSON5}`);
    resModelLoader.setModuleJson(moduleJsonPath, moduleJsonOpt);
    moduleOptionPathInfo.setModuleOptPathMap(moduleJsonPath, moduleJsonOpt?.module, getHookFilePath());
  }

  @TrackAPI getDependenciesOpt(): any {
    return cloneDeep(ohPackageLoader.getDependenciesOpt(this.moduleOhPackagePath));
  }

  @TrackAPI getDevDependenciesOpt(): any {
    return cloneDeep(ohPackageLoader.getDevDependenciesOpt(this.moduleOhPackagePath));
  }

  @TrackAPI getDynamicDependenciesOpt(): any {
    return cloneDeep(ohPackageLoader.getDynamicDependenciesOpt(this.moduleOhPackagePath));
  }

  @TrackAPI setDependenciesOpt(dependencies: any): void {
    ohPackageLoader.setDependenciesOpt(this.moduleOhPackagePath, dependencies);
  }

  @TrackAPI setDevDependenciesOpt(devDependencies: any): void {
    ohPackageLoader.setDevDependenciesOpt(this.moduleOhPackagePath, devDependencies);
  }

  @TrackAPI setDynamicDependenciesOpt(dynamicDependencies: any): void {
    ohPackageLoader.setDynamicDependenciesOpt(this.moduleOhPackagePath, dynamicDependencies);
  }

  @TrackAPI getVersion(): string {
    return ohPackageLoader.getVersion(this.moduleOhPackagePath);
  }

  @TrackAPI setVersion(version: string): void {
    ohPackageLoader.setVersion(this.moduleOhPackagePath, version);
  }

  @TrackAPI loadCompilePlugin(pluginPath: string) {
    ohosTrace.traceIsUseCompilePlugin(this.modulePlugin.getModuleModel()?.getName());
    if (!pluginPath || path.isAbsolute(pluginPath)) {
      this.logger.printErrorExit('IS_NOT_RELATIVE_PATH',[pluginPath]);
    }
    const absolutePath = path.resolve(this.modulePlugin.getModuleModel()!.getModule().getNodeDir(), pluginPath);
    if (!fse.existsSync(absolutePath)) {
      this.logger.printErrorExit('PLUGIN_PATH_NOT_FOUND', [absolutePath]);
    }
    if (!absolutePath.endsWith('.ts')) {
      this.logger.printErrorExit('PLUGIN_FILE_MUST_END_WITH_TS', [absolutePath]);
    }

    // 对插件文件进行语法检查
    doCompilePluginTypeCheck(absolutePath);
    (this.modulePlugin.getModuleModel() as CoreModuleModelImpl)?.setCompilePluginPath(absolutePath);
  }

  @TrackAPI getBuildMode(): string {
    return BuildModeManager.getBuildMode();
  }
}
